# _*_ coding:utf-8 _*_
# @File  : information.py
# @Time  : 2021-07-19  13:17
# @Author: zizle

import datetime

from fastapi import APIRouter, Depends, HTTPException, Path, Query, Body, BackgroundTasks
from pydantic import BaseModel
from db import FAConnection, RedisConnection
from hutool import security
from interfaces.depends import logged_require
from status import r_status
from configs import ADMIN_FLAG, TOKEN_EXPIRES
from category import FUNC_MODULE

info_api = APIRouter()


# # 注册用户
# class RegisterItem(BaseModel):
#     username: str
#     phone: str
#     # password: str
#     # email: str = ''
#     # role: str = 'normal'
#     # input_img_code: str
#     # img_code_uuid: str
#     client_uuid: str

# @info_api.post('/register/')
# async def client_user_register(register_item: RegisterItem = Body(...)):
#     # # 检验验证码
#     # # 验证图片验证码
#     # real_uuid = RedisConnection().get_value(key=f'{register_item.img_code_uuid}')
#     # if str(real_uuid).upper() != str(register_item.input_img_code).upper():
#     #     return {'code': r_status.VALIDATE_ERROR, 'message': '验证码错误!'}
#     # # 解密数据
#     # phone = security.rsa_decrypt(register_item.phone, 0)  # 解密手机
#     # password = security.rsa_decrypt(register_item.password, 0)  # 解密密码
#     # 校验手机号
#     if not re.match(r'^[1345678]{3}[0-9]{8}$', register_item.phone):
#         return {'code': r_status.VALIDATE_ERROR, 'message': '手机号格式有误!'}
#     db = FAConnection(conn_name='用户申请')
#     # 校验客户端
#     query_client = 'SELECT id FROM sys_client WHERE client_code=%s LIMIT 1;'
#     client = db.query(sql=query_client, param=[register_item.client_uuid], keep_conn=True)
#     if not client:
#         db.close()
#         return {'code': r_status.VALIDATE_ERROR, 'message': '无效客户端,申请失败!'}
#     # 校验是否存在
#     query_user = 'SELECT id FROM user_user WHERE phone=%s LIMIT 1;'
#     user_exist = db.query(sql=query_user, param=[register_item.phone], keep_conn=True)
#     if user_exist:
#         db.close()
#         return {'code': r_status.VALIDATE_ERROR, 'message': '该手机号用户已存在!'}
#     # # 密码加密
#     # hash_password = security.cipher_user_password(password)
#     # user_code = 'C_' + create_random_string(10)
#
#     # 存入申请表
#     sql = 'INSERT INTO user_application (username,phone,client_code,is_passed) ' \
#           'VALUES (%s,%s,%s,%s);'
#     count, _ = db.insert(sql, [register_item.username, register_item.phone, register_item.client_uuid, 0])
#     # 返回数据
#     if count:
#         return {'code': r_status.CREATED_SUCCESS, 'message': '申请成功,等待账号发放!'}
#     else:
#         return {'code': r_status.SERVER_ERROR, 'message': '创建用户失败,原因未知!'}


# 记录用户登录日志的后台任务
def log_user_login(user_id: int, t: int):  # t=1为密码登录 t=2为token登录
    db = FAConnection(conn_name='添加登录记录')
    # 查询该用户在2分钟前是否有记录，2分钟内的登录不重复登记
    exist_sql = 'SELECT id FROM user_login_log WHERE (login_time BETWEEN DATE_ADD(NOW(), INTERVAL-2 MINUTE) AND NOW())' \
                'AND user_id=%s;'
    exist = db.query(exist_sql, param=[user_id], fetchone=True, keep_conn=True)[0]
    if exist:
        db.close()
    else:
        db.execute('INSERT INTO user_login_log (login_type,user_id) VALUES (%s,%s);', param=[t, user_id], keep_conn=True)
        # 更新最近登录时间
        db.execute('UPDATE user_user SET recent_login=%s WHERE id=%s;', [datetime.datetime.now(), user_id])


class LoginItem(BaseModel):
    account: str
    password: str
    image_code: str = ''
    image_code_uuid: str = ''
    client_uuid: str = ''


@info_api.post('/login.{login_type}/', summary='用户登录')  # 登录信息在请求info时记录
async def client_user_login(login_type: str = Path(...), login_item: LoginItem = Body(...),
                            auto: int = Query(0, ge=0, le=1)):  # auto是否自动登录
    account = security.rsa_decrypt(login_item.account, 0)  # 解密手机
    password = security.rsa_decrypt(login_item.password, 0)  # 解密密码
    if not all([account, password, login_item.image_code]):
        return {'code': r_status.VALIDATE_ERROR, 'message': '用户名和密码/验证码不能为空!', 'token': '', 'access': []}
    # 验证图片验证码
    real_uuid = RedisConnection().get_value(key=f'{login_item.image_code_uuid}')
    if str(real_uuid).upper() != str(login_item.image_code).upper():
        return {'code': r_status.VALIDATE_ERROR, 'message': '验证码错误!', 'token': '', 'access': []}
    # sql = 'SELECT id,user_code,username,phone,email,password_hashed,role,avatar,expire,clients FROM user_user ' \
    #       'WHERE phone=%s;'
    sql = "SELECT id,ruizy_code,nickname,phone,password,expire,role,role_code,out_role,admin_name FROM ruizy_user " \
          "WHERE phone=%s OR ruizy_code=%s;"
    db = FAConnection(conn_name='User Login')
    user_list = db.query(sql, [account, account])
    token_access = []
    if login_type == 'backadmin':  # 后台管理登录(角色是superuser和operator的)
        # user_list = list(filter(lambda x: x['role'] in ['superuser', 'operator'], user_list))
        user_list = list(filter(lambda x: x['role'] in ['admin', 'admin'], user_list))
        token_access = [ADMIN_FLAG]
    elif login_type == 'web':  # 网页登录
        pass
    elif login_type == 'phone':  # 手机端登录
        pass
    elif login_type == 'client':  # 客户端登录
        pass  # 在密码验证成功的逻辑后执行
    else:
        return {'code': r_status.VALIDATE_ERROR, 'message': '登录方式不支持!', 'token': '', 'access': []}
    if len(user_list) < 1:
        return {'code': r_status.NOT_CONTENT, 'message': '用户不存在或无权限以此方式登录!', 'token': '', 'access': []}
    user_obj = user_list[0]
    # 验证有效性
    if user_obj['expire'].strftime('%Y-%m-%d') < datetime.datetime.today().strftime('%Y-%m-%d'):
        return {'code': r_status.VALIDATE_ERROR, 'message': '使用期已过,您暂时无法登录!\n请联系客服微信【rqyjkf】.', 'token': '', 'access': []}
    # if user_obj['role'] in ['superuser', 'operator']:
    #     token_access = [ADMIN_FLAG]
    if user_obj['role'] in ['admin', 'admin']:
        token_access = [ADMIN_FLAG]
    # 验证密码
    is_password_correct = security.decipher_user_password(password, user_obj['password'])
    if is_password_correct:
        token_data = {
            'uid': user_obj['id'],
            'access': token_access,
            'role': user_obj['role'],
            'role_code': user_obj['role_code'],
            'out_role': user_obj['out_role'],
            'user_id': user_obj['id'],  # 旧版接口使用
            'user_code': user_obj['ruizy_code']  # 旧版接口使用
        }
        # 发放token
        token = security.create_access_token(token_data, expire_seconds=TOKEN_EXPIRES)
        db = FAConnection(conn_name='UpdateLoginTime')
        # 如果是客户端登录,检测能否登录,将此用户的名称更新到客户端最近登录人之中
        if login_type == 'client':
            # 1 检测能否登录,绑定客户端检测20220701关闭
            # if user_obj['role'] not in ['superuser', 'operator', 'collector', 'research']:
            #     auth_clients = user_obj['clients']
            #     if not auth_clients:  # 没有绑定客户端就绑定客户端
            #         db.execute('UPDATE user_user SET clients=%s WHERE id=%s LIMIT 1;',
            #                    [login_item.client_uuid, user_obj['id']], keep_conn=True)
            #     else:  # 验证可登录的客户端
            #         permission_clients = auth_clients.split(';')
            #         if login_item.client_uuid not in permission_clients:
            #             db.close()
            #             return {'code': r_status.FORBIDDEN, 'message': f'您无法登录此客户端!\n编号:{login_item.client_uuid}',
            #                     'token': '', 'access': []}
            # 2 能登录写入登录人
            username = user_obj['admin_name'] if user_obj['admin_name'] else user_obj['ruizy_code']
            db.execute('UPDATE sys_client SET user_login=%s WHERE client_code=%s;', [username, login_item.client_uuid])
        else:
            db.close()
        user_obj['username'] = user_obj['nickname'] if user_obj['nickname'] else user_obj['ruizy_code']
        return {'code': r_status.SUCCESS, 'message': '登录成功!', 'token': token, 'access': token_access}
    else:
        return {'code': r_status.VALIDATE_ERROR, 'message': '用户名或密码错误!', 'token': '', 'access': []}


@info_api.get('/user.info/', summary='使用token获取用户信息')
async def get_user_information(background_task: BackgroundTasks, person: dict = Depends(logged_require)):
    if not person.get('role_code'):
        raise HTTPException(status_code=401, detail='login expired')
    user_id = person['uid']
    db = FAConnection(conn_name='查询用户信息')
    # sql = 'SELECT id,username,user_code,phone,email,role,expire FROM user_user WHERE id=%s;'
    sql = 'SELECT id,nickname,ruizy_code,phone,role,expire FROM ruizy_user WHERE id=%s;'
    user_list = db.query(sql, [user_id])
    if len(user_list) < 1:
        db.close()
        raise HTTPException(status_code=401, detail='login expired')
    user_obj = user_list[0]
    user_obj['username'] = user_obj['nickname'] if user_obj['nickname'] else user_obj['ruizy_code']
    # 验证下有效期
    if user_obj['expire'].strftime('%Y-%m-%d') < datetime.datetime.today().strftime('%Y-%m-%d'):
        raise HTTPException(status_code=401, detail='login expired,user no active!')
    # 检测过期时间
    tips = ''
    if (user_obj['expire'] - datetime.date.today()).days < 3:  # 明天过后过期
        tips = '您的使用期即将到期。\n为保证您能继续使用，请尽快联系客服进行延期!\n客服微信号【rqyjkf】.'
    # 添加登录记录
    background_task.add_task(log_user_login, user_id=user_id, t=2)
    return {'code': r_status.SUCCESS, 'message': '获取用户信息成功!', 'data': user_obj, 'tips': tips}


@info_api.get('/user.variety/', summary='查询用户的权限品种')
async def get_user_variety(person: dict = Depends(logged_require), ex: int = Query(0, ge=0, le=1)):
    is_all = False
    if ADMIN_FLAG in person['access'] or person['uid'] == 17:
        sql = 'SELECT id,variety_en,variety_name,exchange FROM sys_variety WHERE is_active=1;'
        param = None
        is_all = True
    else:
        sql = 'SELECT v.id,v.variety_en,v.variety_name,v.exchange,p.expire_date ' \
              'FROM sys_variety AS v ' \
              'INNER JOIN user_user_variety AS p ON v.variety_en=p.variety_en ' \
              'WHERE p.user_id=%s AND v.is_active=1;'
        param = [person['uid']]
    db = FAConnection(conn_name='QueryPersonVariety')
    records = db.query(sql, param)
    rep_data = []
    if not is_all:
        # 过滤掉已过期的
        today_str = datetime.datetime.today().strftime('%Y-%m-%d')
        for item in records:
            if item.get('expire_date') and item['expire_date'] < today_str:
                continue
            rep_data.append(item)
    else:
        rep_data = records
    if ex:
        rep_data = list(filter(lambda x: x['exchange'] != 6, rep_data))
    return {'code': r_status.SUCCESS, 'message': '查询用户权限品种成功!', 'data': rep_data}


@info_api.put('/user/password/', summary='用户修改密码')
async def modify_user_password(person: dict = Depends(logged_require), modify_item: dict = Body(...)):
    phone = modify_item.get('phone')
    old_psd = modify_item.get('old_password')
    new_psd = modify_item.get('new_password')
    if not all([phone, old_psd, new_psd]):
        return {'code': r_status.VALIDATE_ERROR, 'message': '参数错误,请填写完整信息!'}
    phone = security.rsa_decrypt(phone, 0)  # 解密手机
    # 查询用户对象
    sql = 'SELECT id,user_code,username,phone,email,password_hashed,role,avatar,expire,clients FROM user_user ' \
          'WHERE phone=%s;'
    db = FAConnection(conn_name='修改密码')
    user_list = db.query(sql, [phone], keep_conn=True)
    if not user_list:
        db.close()
        return {'code': r_status.NOT_CONTENT, 'message': '用户不存在!'}
    user_obj = user_list[0]
    # 验证原密码是否正确
    if not security.decipher_user_password(old_psd, user_obj['password_hashed']):
        db.close()
        return {'code': r_status.VALIDATE_ERROR, 'message': '原密码错误!'}
    new_psd = security.rsa_decrypt(new_psd, 0)  # 解密新密码
    new_password_hashed = security.cipher_user_password(new_psd)   # 新密码hash化
    # 修改密码
    update_sql = 'UPDATE user_user SET password_hashed=%s WHERE id=%s LIMIT 1;'
    _, success = db.execute(update_sql, param=[new_password_hashed, user_obj['id']])
    if success:
        return {'code': r_status.SUCCESS, 'message': '修改成功,请重新登录!'}
    return {'code': r_status.VALIDATE_ERROR, 'message': '修改失败了,服务器错误!'}


@info_api.post('/user/func-module/', summary='记录用户访问的功能模块')
async def log_user_enter_module(person: dict = Depends(logged_require), module_name: str = Body(..., embed=True)):
    if person['role'] != 'normal':  # 只记录客户端用户的足迹
        return {'code': r_status.SUCCESS, 'message': '无需记录!', 'data': []}
    if module_name not in FUNC_MODULE.keys():
        return {'code': r_status.VALIDATE_ERROR, 'message': '无需记录!', 'data': []}
    db = FAConnection(conn_name='记录足迹')
    # 5分钟内有记录不再登记
    exist_sql = 'SELECT id FROM user_func_module_log WHERE (enter_time BETWEEN DATE_ADD(NOW(), INTERVAL-5 MINUTE) ' \
                'AND NOW()) AND user_id=%s AND func_name=%s;'
    exist = db.query(exist_sql, param=[person['uid'], module_name], fetchone=True, keep_conn=True)[0]
    if exist:
        db.close()
    else:
        db.insert('INSERT INTO user_func_module_log (func_name,user_id) VALUES (%s,%s);', param=[module_name, person['uid']])
    return {'code': r_status.SUCCESS, 'message': '记录成功!', 'data': []}
